home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / dwuninst.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  19.3 KB  |  861 lines

  1. /* Copyright (C) 1999, Ghostgum Software Pty Ltd.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. // $Id: dwuninst.cpp,v 1.2 2000/09/19 19:00:10 lpd Exp $
  20.  
  21. #define STRICT
  22. #include <windows.h>
  23. #include <objbase.h>
  24. #include <shlobj.h>
  25. #include <shellapi.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <direct.h>
  30. #include "dwuninst.h"
  31.  
  32.  
  33. #ifdef _MSC_VER
  34. #define _export
  35. #define chdir(x) _chdir(x)
  36. #define mkdir(x) _mkdir(x)
  37. #endif
  38. #define DELAY_STEP 500
  39. #define DELAY_FILE 5
  40. #define MAXSTR 256
  41. #define UNINSTALLKEY TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
  42.  
  43. HWND hDlgModeless;
  44. HWND hText1;
  45. HWND hText2;
  46. char path[MAXSTR];
  47. int language = 0;
  48. BOOL is_win4 = FALSE;
  49. HINSTANCE phInstance;
  50. char szSection[] = "////////////////////////////////";
  51. BOOL bQuit = FALSE;
  52. BOOL gError = FALSE;    // set TRUE if an uninstall was not successful 
  53.  
  54. char szTitle[MAXSTR];
  55. char szLogFile[MAXSTR];
  56. char szLine[MAXSTR];
  57. FILE *fLog;
  58.  
  59. void do_message(void);
  60. BOOL dofiles(void);
  61. BOOL registry_delete(void);
  62. BOOL registry_import(void);
  63. BOOL shell_new(void);
  64. BOOL shell_old(void);
  65. BOOL doEOF(void);
  66.  
  67. // #define gs_addmess(str) fputs(str, stdout)    // for debug 
  68. #define gs_addmess(str)
  69.  
  70.  
  71. // linked list for deleting registry entries in reverse order
  72. typedef struct tagKEY {
  73.     long index;
  74.     struct tagKEY *previous;
  75. } KEY;
  76. KEY *last_key = NULL;
  77.  
  78.  
  79. // read a line from the log, removing trailing new line character
  80. BOOL GetLine(void)
  81. {
  82.     BOOL err = TRUE;
  83.     int i;
  84.     szLine[0] = '\0';
  85.     if (fLog)
  86.         err = (fgets(szLine, sizeof(szLine)-1, fLog) == NULL);
  87.     i = strlen(szLine) - 1;
  88.     if ( (szLine[0] != '\0') && (szLine[i] == '\n'))
  89.         szLine[i] = '\0';
  90.     return !err;
  91. }
  92.  
  93. BOOL IsSection(void)
  94. {
  95.     return (strncmp(szLine, szSection, strlen(szSection)) == 0);
  96. }
  97.  
  98. BOOL
  99. NextSection(void)
  100. {
  101.     while (GetLine()) {
  102.         do_message();
  103.         if (bQuit)
  104.             return FALSE;
  105.         if (IsSection())
  106.             return TRUE;
  107.     }
  108.  
  109.     return TRUE;
  110. }
  111.  
  112. BOOL ReadSection(void)
  113. {
  114.     do_message();
  115.     if (bQuit)
  116.         return FALSE;
  117.     GetLine();
  118.     if (strlen(szLine) == 0) {
  119.         doEOF();
  120.         return TRUE;
  121.     }
  122.     else if (strcmp(szLine, "FileNew")==0) {
  123.         SetWindowText(hText1, "Removing Files");
  124.         Sleep(DELAY_STEP);
  125.         if (!dofiles())
  126.             return FALSE;
  127.         SetWindowText(hText1, "");
  128.         return TRUE;
  129.     }
  130.     else if (strcmp(szLine, "RegistryNew")==0) {
  131.         SetWindowText(hText1, "Removing Registry entries");
  132.         Sleep(DELAY_STEP);
  133.         if (!registry_delete())
  134.             return FALSE;
  135.         SetWindowText(hText1, "");
  136.         return TRUE;
  137.     }
  138.     else if (strcmp(szLine, "RegistryOld")==0) {
  139.         SetWindowText(hText1, "Restoring Registry entries");
  140.         Sleep(DELAY_STEP);
  141.         if (!registry_import())
  142.             return FALSE;
  143.         SetWindowText(hText1, "");
  144.         return TRUE;
  145.     }
  146.     else if (strcmp(szLine, "ShellNew")==0) {
  147.         SetWindowText(hText1, "Removing Start Menu items");
  148.         Sleep(DELAY_STEP);
  149.         if (!shell_new())
  150.             return FALSE;
  151.         SetWindowText(hText1, "");
  152.         return TRUE;
  153.     }
  154.     else if (strcmp(szLine, "ShellOld")==0) {
  155.         SetWindowText(hText1, "Restoring Start Menu items");
  156.         Sleep(DELAY_STEP);
  157.         if (!shell_old())
  158.             return FALSE;
  159.         SetWindowText(hText1, "");
  160.         return TRUE;
  161.     }
  162.     return FALSE;
  163. }
  164.  
  165.  
  166. BOOL
  167. dofiles(void)
  168. {
  169.     while (GetLine()) {
  170.     do_message();
  171.     if (bQuit)
  172.         return FALSE;
  173.     if (IsSection()) {
  174.         SetWindowText(hText2, "");
  175.         return TRUE;
  176.     }
  177.     if (szLine[0] != '\0') {
  178.         SetWindowText(hText2, szLine);
  179.         Sleep(DELAY_FILE);
  180.         gs_addmess("Deleting File: ");
  181.         gs_addmess(szLine);
  182.         gs_addmess("\n");
  183.         DeleteFile(szLine);
  184.     }
  185.     }
  186.     return FALSE;
  187. }
  188.  
  189. BOOL
  190. doEOF(void)
  191. {
  192.     fclose(fLog);
  193.     fLog = NULL;
  194.     unlink(szLogFile);
  195.     PostMessage(hDlgModeless, WM_COMMAND, IDC_DONE, 0L);
  196.     bQuit = TRUE;
  197.     return TRUE;
  198. }
  199.  
  200.  
  201. BOOL
  202. registry_delete_key(void)
  203. {
  204. char keyname[MAXSTR];
  205. HKEY hkey = HKEY_CLASSES_ROOT;
  206. HKEY hrkey = HKEY_CLASSES_ROOT;
  207. char *rkey, *skey;
  208. char *name;
  209. DWORD dwResult;
  210.     keyname[0] = '\0';
  211.     while (GetLine()) {
  212.     if ((szLine[0] == '\0') || (szLine[0] == '\r') || (szLine[0] == '\n'))
  213.         break;
  214.     if (szLine[0] == '[') {
  215.         // key name
  216.         rkey = strtok(szLine+1, "\\]\n\r");
  217.         if (rkey == (char *)NULL)
  218.         return FALSE;
  219.         skey = strtok(NULL, "]\n\r");
  220.         if (strcmp(rkey, "HKEY_CLASSES_ROOT")==0)
  221.         hrkey = HKEY_CLASSES_ROOT;
  222.         else if (strcmp(rkey, "HKEY_CURRENT_USER")==0)
  223.         hrkey = HKEY_CURRENT_USER;
  224.         else if (strcmp(rkey, "HKEY_LOCAL_MACHINE")==0)
  225.         hrkey = HKEY_LOCAL_MACHINE;
  226.         else if (strcmp(rkey, "HKEY_USERS")==0)
  227.         hrkey = HKEY_USERS;
  228.         else
  229.         return FALSE;
  230.         if (skey == (char *)NULL)
  231.         return FALSE;
  232.         gs_addmess("Opening registry key\n   ");
  233.         gs_addmess(rkey);
  234.         gs_addmess("\\");
  235.         gs_addmess(skey);
  236.         gs_addmess("\n");
  237.         if (RegCreateKeyEx(hrkey, skey, 0, "", 0, KEY_ALL_ACCESS, 
  238.         NULL, &hkey, &dwResult)
  239.         != ERROR_SUCCESS)
  240.         return FALSE;
  241.         strcpy(keyname, skey);
  242.     }
  243.     else if (szLine[0] == '@') {
  244.         // default value
  245.         RegDeleteValue(hkey, NULL);
  246.         gs_addmess("Deleting registry default value\n");
  247.     }
  248.     else if (szLine[0] == '\042') {
  249.         // named value
  250.         name = strtok(szLine+1, "\042\r\n");
  251.         RegDeleteValue(hkey, name);
  252.         gs_addmess("Deleting registry named value\n   ");
  253.         gs_addmess(name);
  254.         gs_addmess("\n");
  255.     }
  256.     }
  257.     // close key
  258.     if (hkey != HKEY_CLASSES_ROOT)
  259.     RegCloseKey(hkey);
  260.     // delete the key
  261.     if (strlen(keyname)) {
  262.     gs_addmess("Deleting registry key\n   ");
  263.     gs_addmess(keyname);
  264.     gs_addmess("\n");
  265.     RegOpenKeyEx(hrkey, NULL, 0, 0, &hkey);
  266.     RegDeleteKey(hkey, keyname);
  267.     RegCloseKey(hkey);
  268.     }
  269.     return TRUE;
  270. }
  271.  
  272. BOOL
  273. registry_delete()
  274. {
  275.     long logindex;
  276.     KEY *key;
  277.     
  278.     // scan log file
  279.     // so we can remove keys in reverse order
  280.     logindex = 0;
  281.     while (GetLine() && !IsSection()) {
  282.         KEY *key;
  283.         if (szLine[0] == '[') {
  284.             if ((key = (KEY *)malloc(sizeof(KEY)))
  285.                 != (KEY *)NULL) {
  286.                 key->previous = last_key;
  287.                 key->index = logindex;
  288.                 last_key = key;
  289.             }
  290.         }
  291.         logindex = ftell(fLog);
  292.     }
  293.     
  294.     // Remove keys
  295.     for (key = last_key; key != NULL; 
  296.     key = key->previous) {
  297.         if (key != last_key)
  298.             free(last_key);
  299.         fseek(fLog, key->index, SEEK_SET);
  300.         registry_delete_key();
  301.         last_key = key;
  302.     }
  303.     free(last_key);
  304.     
  305.     fseek(fLog, logindex, SEEK_SET);
  306.     GetLine();
  307.     return TRUE;
  308. }
  309.  
  310.  
  311.  
  312. void
  313. registry_unquote(char *line)
  314. {
  315. char *s, *d;
  316. int value;
  317.     s = d = line;
  318.     while (*s) {
  319.     if (*s != '\\') {
  320.         *d++ = *s;
  321.     }
  322.     else {
  323.         s++;
  324.         if (*s == '\\')
  325.         *d++ = *s;
  326.         else {
  327.         value = 0;
  328.         if (*s) {
  329.             value = *s++ - '0';
  330.         }
  331.         if (*s) {
  332.             value <<= 3;
  333.             value += *s++ - '0';
  334.         }
  335.         if (*s) {
  336.             value <<= 3;
  337.             value += *s - '0';
  338.         }
  339.         *d++ = (char)value;
  340.         }
  341.     }
  342.     s++;
  343.     }
  344.     *d = '\0';
  345. }
  346.  
  347. BOOL
  348. registry_import()
  349. {
  350.     HKEY hkey = HKEY_CLASSES_ROOT;
  351.     HKEY hrkey;
  352.     char *rkey, *skey;
  353.     char *value;
  354.     char *name;
  355.     DWORD dwResult;
  356.     GetLine();
  357.     if (strncmp(szLine, "REGEDIT4", 8) != 0)
  358.         return FALSE;
  359.     
  360.     while (GetLine()) {
  361.         if (IsSection())
  362.             break;
  363.         if ((szLine[0] == '\0') || (szLine[0] == '\r') || (szLine[0] == '\n'))
  364.             continue;
  365.         if (szLine[0] == '[') {
  366.             // key name
  367.             if (hkey != HKEY_CLASSES_ROOT) {
  368.                 RegCloseKey(hkey);
  369.                 hkey = HKEY_CLASSES_ROOT;
  370.             }
  371.             rkey = strtok(szLine+1, "\\]\n\r");
  372.             if (rkey == (char *)NULL)
  373.                 return FALSE;
  374.             skey = strtok(NULL, "]\n\r");
  375.             if (strcmp(rkey, "HKEY_CLASSES_ROOT")==0)
  376.                 hrkey = HKEY_CLASSES_ROOT;
  377.             else if (strcmp(rkey, "HKEY_CURRENT_USER")==0)
  378.                 hrkey = HKEY_CURRENT_USER;
  379.             else if (strcmp(rkey, "HKEY_LOCAL_MACHINE")==0)
  380.                 hrkey = HKEY_LOCAL_MACHINE;
  381.             else if (strcmp(rkey, "HKEY_USERS")==0)
  382.                 hrkey = HKEY_USERS;
  383.             else
  384.                 return FALSE;
  385.             if (skey == (char *)NULL)
  386.                 return FALSE;
  387.             gs_addmess("Creating registry key\n   ");
  388.             gs_addmess(rkey);
  389.             gs_addmess("\\");
  390.             gs_addmess("skey");
  391.             gs_addmess("\n");
  392.             if (RegCreateKeyEx(hrkey, skey, 0, "", 0, KEY_ALL_ACCESS, 
  393.                 NULL, &hkey, &dwResult)
  394.                 != ERROR_SUCCESS)
  395.                 return FALSE;
  396.         }
  397.         else if (szLine[0] == '@') {
  398.             // default value
  399.             if (strlen(szLine) < 4)
  400.                 return FALSE;
  401.             value = strtok(szLine+3, "\042\r\n");
  402.             if (value) {
  403.                 registry_unquote(value);
  404.                 gs_addmess("Setting registry key value\n   ");
  405.                 gs_addmess(value);
  406.                 gs_addmess("\n");
  407.                 if (RegSetValueEx(hkey, NULL, 0, REG_SZ, 
  408.                     (CONST BYTE *)value, strlen(value)+1)
  409.                     != ERROR_SUCCESS)
  410.                     return FALSE;
  411.             }
  412.         }
  413.         else if (szLine[0] == '\042') {
  414.             // named value
  415.             name = strtok(szLine+1, "\042\r\n");
  416.             strtok(NULL, "\042\r\n");
  417.             value = strtok(NULL, "\042\r\n");
  418.             registry_unquote(value);
  419.             gs_addmess("Setting registry key value\n   ");
  420.             gs_addmess(name);
  421.             gs_addmess("=");
  422.             gs_addmess(value);
  423.             gs_addmess("\n");
  424.             if (RegSetValueEx(hkey, name, 0, REG_SZ, (CONST BYTE *)value, strlen(value)+1)
  425.                 != ERROR_SUCCESS)
  426.                 return FALSE;
  427.         }
  428.     }
  429.     if (hkey != HKEY_CLASSES_ROOT)
  430.         RegCloseKey(hkey);
  431.     return TRUE;
  432. }
  433.  
  434. // recursive mkdir
  435. // requires a full path to be specified, so ignores root \ 
  436. // apart from root \, must not contain trailing \ 
  437. // Examples:
  438. //  c:\          (OK, but useless)
  439. //  c:\gstools   (OK)
  440. //  c:\gstools\  (incorrect)
  441. //  c:gstools    (incorrect)
  442. //  gstools      (incorrect)
  443. // The following UNC names should work,
  444. // but didn't under Win3.1 because gs_chdir wouldn't accept UNC names
  445. // Needs to be tested under Windows 95.
  446. //  \\server\sharename\gstools    (OK)
  447. //  \\server\sharename\           (OK, but useless)
  448. //
  449.  
  450. BOOL MakeDir(char *dirname)
  451. {
  452. char newdir[MAXSTR];
  453. char *p;
  454.     if (strlen(dirname) < 3)
  455.         return -1;
  456.  
  457.     gs_addmess("Making Directory\n  ");
  458.     gs_addmess(dirname);
  459.     gs_addmess("\n");
  460.     if (isalpha(dirname[0]) && dirname[1]==':' && dirname[2]=='\\') {
  461.         // drive mapped path
  462.         p = dirname+3;
  463.     }
  464.     else if (dirname[1]=='\\' && dirname[1]=='\\') {
  465.         // UNC path
  466.         p = strchr(dirname+2, '\\');    // skip servername
  467.         if (p == NULL)
  468.             return -1;
  469.         p++;
  470.         p = strchr(p, '\\');            // skip sharename
  471.         if (p == NULL)
  472.             return -1;
  473.     }
  474.     else {
  475.         // not full path so error
  476.         return -1;
  477.     }
  478.  
  479.     while (1) {
  480.         strncpy(newdir, dirname, (int)(p-dirname));
  481.         newdir[(int)(p-dirname)] = '\0';
  482.         if (chdir(newdir)) {
  483.             if (mkdir(newdir))
  484.                 return -1;
  485.         }
  486.         p++;
  487.         if (p >= dirname + strlen(dirname))
  488.             break;              // all done
  489.         p = strchr(p, '\\');
  490.         if (p == NULL)
  491.             p = dirname + strlen(dirname);
  492.     }
  493.  
  494.     return SetCurrentDirectory(dirname);
  495. }
  496.  
  497.  
  498. BOOL shell_new(void)
  499. {
  500.  
  501.     char *p, *q;
  502.     char group[MAXSTR];
  503.     // remove shell items added by Ghostscript
  504.     // We can only delete one group with this code
  505.     group[0] = '\0';
  506.     while (GetLine()) {
  507.         if (IsSection()) {
  508.             if (strlen(group) != 0) {
  509.                 gs_addmess("Removing shell folder\n  ");
  510.                 gs_addmess(group);
  511.                 gs_addmess("\n");
  512.                 RemoveDirectory(group);
  513.             }
  514.             return TRUE;
  515.         }
  516.         p = strtok(szLine, "=");
  517.         q = strtok(NULL, "");
  518.         if (p == NULL) {
  519.             continue;
  520.         }
  521.         else if (strcmp(p, "Group")==0) {
  522.             if (q)
  523.                 strncpy(group, q, sizeof(group)-1);
  524.             // defer this until we have remove contents
  525.         }
  526.         else if (strcmp(p, "Name") == 0) {
  527.             if (q) {
  528.                 gs_addmess("Removing shell link\n  ");
  529.                 gs_addmess(q);
  530.                 gs_addmess("\n");
  531.                 DeleteFile(q);
  532.             }
  533.         }
  534.     }
  535.  
  536.     return TRUE;
  537. }
  538.  
  539.  
  540. BOOL CreateShellLink(LPCSTR name, LPCSTR description, LPCSTR program, 
  541.     LPCSTR arguments, LPCSTR directory, LPCSTR icon, int nIconIndex)
  542. {
  543.     HRESULT hres;    
  544.     IShellLink* psl;
  545.  
  546.     // Ensure string is UNICODE.
  547.     WCHAR wsz[MAX_PATH];
  548.     MultiByteToWideChar(CP_ACP, 0, name, -1, wsz, MAX_PATH);
  549.  
  550.     // Save new shell link
  551.  
  552.     // Get a pointer to the IShellLink interface.
  553.     hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  554.         IID_IShellLink, (void **)&psl);
  555.     if (SUCCEEDED(hres))    {
  556.         IPersistFile* ppf;
  557.         // Query IShellLink for the IPersistFile interface for 
  558.         // saving the shell link in persistent storage.
  559.         hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
  560.         if (SUCCEEDED(hres)) {            
  561.             gs_addmess("Adding shell link\n  ");
  562.             gs_addmess(name);
  563.             gs_addmess("\n");
  564.  
  565.             // Set the path to the shell link target.
  566.             hres = psl->SetPath(program);         
  567.             if (!SUCCEEDED(hres)) {
  568.                 gs_addmess("SetPath failed!");
  569.                 gError = TRUE;
  570.             }
  571.             // Set the description of the shell link.
  572.             hres = psl->SetDescription(description);         
  573.             if (!SUCCEEDED(hres)) {
  574.                 gs_addmess("SetDescription failed!");
  575.                 gError = TRUE;
  576.             }
  577.             if ((arguments != (LPCSTR)NULL) && *arguments) {
  578.                 // Set the arguments of the shell link target.
  579.                 hres = psl->SetArguments(arguments);         
  580.                 if (!SUCCEEDED(hres)) {
  581.                     gs_addmess("SetArguments failed!");
  582.                     gError = TRUE;
  583.                 }
  584.             }
  585.             if ((directory != (LPCSTR)NULL) && *directory) {
  586.                 // Set the arguments of the shell link target.
  587.                 hres = psl->SetWorkingDirectory(directory);         
  588.                 if (!SUCCEEDED(hres)) {
  589.                     gs_addmess("SetWorkingDirectory failed!");
  590.                     gError = TRUE;
  591.                 }
  592.             }
  593.             if ((icon != (LPCSTR)NULL) && *icon) {
  594.                 // Set the arguments of the shell link target.
  595.                 hres = psl->SetIconLocation(icon, nIconIndex);         
  596.                 if (!SUCCEEDED(hres)) {
  597.                     gs_addmess("SetIconLocation failed!");
  598.                     gError = TRUE;
  599.                 }
  600.             }
  601.  
  602.             // Save the link via the IPersistFile::Save method.
  603.             hres = ppf->Save(wsz, TRUE);    
  604.             // Release pointer to IPersistFile.         
  605.             ppf->Release();
  606.         }
  607.         // Release pointer to IShellLink.       
  608.         psl->Release();    
  609.     }
  610.  
  611.     return (hres == 0);
  612. }
  613.  
  614.  
  615.  
  616. BOOL shell_old(void)
  617. {
  618.     // Add shell items removed by Ghostscript
  619.     char *p, *q;
  620.     char name[MAXSTR];
  621.     char description[MAXSTR];
  622.     char program[MAXSTR];
  623.     char arguments[MAXSTR];
  624.     char directory[MAXSTR];
  625.     char icon[MAXSTR];
  626.     int nIconIndex;
  627.     // Remove shell items added by Ghostscript
  628.     name[0] = description[0] = program[0] = arguments[0] 
  629.         = directory[0] = icon[0] = '\0';
  630.     nIconIndex = 0;
  631.     
  632.     while (GetLine()) {
  633.         if (IsSection())
  634.             return TRUE;
  635.         p = strtok(szLine, "=");
  636.         q = strtok(NULL, "");
  637.         if (strlen(szLine) == 0) {
  638.             if (name[0] != '\0') {
  639.                 // add start menu item
  640.                 CreateShellLink(name, description, program, arguments, 
  641.                     directory, icon, nIconIndex);
  642.             }
  643.             name[0] = description[0] = program[0] = arguments[0] 
  644.                 = directory[0] = icon[0] = '\0';
  645.             nIconIndex = 0;
  646.             continue;
  647.         }
  648.         else if (p == (char *)NULL) {
  649.             continue;
  650.         }
  651.         else if (strcmp(p, "Group")==0) {
  652.             MakeDir(q);
  653.         }
  654.         else if (strcmp(p, "Name") == 0)
  655.             strncpy(name, q, sizeof(name)-1);
  656.         else if (strcmp(p, "Description") == 0)
  657.             strncpy(description, q, sizeof(description)-1);
  658.         else if (strcmp(p, "Program") == 0)
  659.             strncpy(program, q, sizeof(program)-1);
  660.         else if (strcmp(p, "Arguments") == 0)
  661.             strncpy(arguments, q, sizeof(arguments)-1);
  662.         else if (strcmp(p, "Directory") == 0)
  663.             strncpy(directory, q, sizeof(directory)-1);
  664.         else if (strcmp(p, "IconLocation") == 0)
  665.             strncpy(icon, q, sizeof(icon)-1);
  666.         else if (strcmp(p, "IconIndex") == 0)
  667.             nIconIndex = atoi(q);
  668.     }
  669.     
  670.     return TRUE;
  671. }
  672.  
  673.  
  674.  
  675. #ifdef __BORLANDC__
  676. #pragma argsused
  677. #endif
  678. BOOL CALLBACK _export
  679. RemoveDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  680. {
  681.   switch(message) {
  682.     case WM_INITDIALOG:
  683.         SetWindowText(hwnd, szTitle);
  684.         return TRUE;
  685.     case WM_COMMAND:
  686.         switch(LOWORD(wParam)) {
  687.         case IDC_DONE:
  688.             // delete registry entries for uninstall
  689.             if (is_win4) {
  690.                 HKEY hkey;
  691.                 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
  692.                     UNINSTALLKEY, 0, KEY_ALL_ACCESS, &hkey) 
  693.                     == ERROR_SUCCESS) {
  694.                     RegDeleteKey(hkey, szTitle);
  695.                     RegCloseKey(hkey);
  696.                 }
  697.             }
  698.  
  699.             SetWindowText(hText1, "Uninstall successful");
  700.             SetWindowText(hText2, "");
  701.             EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
  702.             EnableWindow(GetDlgItem(hwnd, IDCANCEL), TRUE);
  703.             SetDlgItemText(hwnd, IDCANCEL, "Exit");
  704.             SetFocus(GetDlgItem(hwnd, IDCANCEL));
  705.             return TRUE;
  706.         case IDOK:
  707.             // Start removal
  708.             EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
  709.             EnableWindow(GetDlgItem(hwnd, IDC_PRESSOK), FALSE);
  710.             while (!bQuit) {
  711.             do_message();
  712.             if (!ReadSection()) {
  713.                 SetWindowText(hText1, "Uninstall FAILED");
  714.                 SetWindowText(hText2, "");
  715.                 EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
  716.                 EnableWindow(GetDlgItem(hwnd, IDCANCEL), TRUE);
  717.                 SetDlgItemText(hwnd, IDCANCEL, "Exit");
  718.                 SetFocus(GetDlgItem(hwnd, IDCANCEL));
  719.                 bQuit = TRUE;
  720.             }
  721.             }
  722.             return TRUE;
  723.         case IDCANCEL:
  724.             bQuit = TRUE;
  725.             DestroyWindow(hwnd);
  726.             hDlgModeless = 0;
  727.             return TRUE;
  728.         }
  729.     case WM_CLOSE:
  730.         DestroyWindow(hwnd);
  731.         hDlgModeless = 0;
  732.         return TRUE;
  733.     }
  734.     return FALSE;
  735. }
  736.  
  737. void
  738. do_message(void)
  739. {
  740. MSG msg;
  741.     while (hDlgModeless && PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE)) {
  742.     if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  743.         TranslateMessage(&msg);
  744.         DispatchMessage(&msg);
  745.     }
  746.     }
  747. }
  748.  
  749.  
  750.  
  751. BOOL
  752. init(void)
  753. {
  754.     DWORD version = GetVersion();
  755.     char *p, *s;
  756.     // get location of uninstall log from command line as argv[1]
  757.     p = GetCommandLine();
  758.     s = p;
  759.     if (*s == '\042') {
  760.         // skip over program name
  761.         s++;
  762.         while (*s && *s!='\042')
  763.             s++;
  764.         if (*s)
  765.             s++;
  766.     }
  767.     else if (*s != ' ') {
  768.         // skip over program name
  769.         s++;
  770.         while (*s && *s!=' ')
  771.             s++;
  772.         if (*s)
  773.             s++;
  774.     }
  775.     while (*s && *s==' ')
  776.         s++;
  777.     if (*s == '\042')
  778.         s++;
  779.     strncpy(szLogFile, s, sizeof(szLogFile));
  780.     s = szLogFile;
  781.     while (*s) {
  782.         if (*s == '\042') {
  783.             *s = '\0';
  784.             break;
  785.         }
  786.         s++;
  787.     }
  788.     if (strlen(szLogFile) == 0) {
  789.         MessageBox(HWND_DESKTOP, "Usage: uninstgs logfile.txt", 
  790.             "AFPL Ghostscript Uninstall", MB_OK);
  791.         return FALSE;
  792.     }
  793.     
  794.     // read first few lines of file to get title
  795.     fLog = fopen(szLogFile, "r");
  796.     if (fLog == (FILE *)NULL) {
  797.         MessageBox(HWND_DESKTOP, szLogFile, "Can't find file", MB_OK);
  798.         return FALSE;
  799.     }
  800.     GetLine();
  801.     if (!IsSection()) {
  802.         MessageBox(HWND_DESKTOP, szLogFile, "Not valid uninstall log", 
  803.             MB_OK);
  804.         return FALSE;
  805.     }
  806.     GetLine();
  807.     if (strcmp(szLine, "UninstallName") != 0) {
  808.         MessageBox(HWND_DESKTOP, szLogFile, "Not valid uninstall log", 
  809.             MB_OK);
  810.         return FALSE;
  811.     }
  812.     GetLine();
  813.     strcpy(szTitle, szLine);
  814.     
  815.     NextSection();
  816.     
  817.     if (LOBYTE(LOWORD(version)) >= 4)
  818.         is_win4 = TRUE;
  819.     return TRUE;
  820. }
  821.  
  822. #ifdef __BORLANDC__
  823. #pragma argsused
  824. #endif
  825. int PASCAL 
  826. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
  827. {
  828. MSG msg;
  829.  
  830.     phInstance = hInstance;
  831.     if (!init())
  832.     return 1;
  833.  
  834.  
  835.     CoInitialize(NULL);
  836.  
  837.     hDlgModeless = CreateDialogParam(hInstance, 
  838.         MAKEINTRESOURCE(IDD_UNSET),
  839.         HWND_DESKTOP, RemoveDlgProc, (LPARAM)NULL);
  840.     hText1 = GetDlgItem(hDlgModeless, IDC_T1);
  841.     hText2 = GetDlgItem(hDlgModeless, IDC_T2);
  842.  
  843.     SetWindowPos(hDlgModeless, HWND_TOP, 0, 0, 0, 0, 
  844.     SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
  845.  
  846.     while (hDlgModeless && GetMessage(&msg, (HWND)NULL, 0, 0)) {
  847.     if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  848.         TranslateMessage(&msg);
  849.         DispatchMessage(&msg);
  850.     }
  851.     }
  852.  
  853.     if (fLog)
  854.         fclose(fLog);
  855.     
  856.     CoUninitialize();
  857.  
  858.     return 0;
  859. }
  860.  
  861.